package com.appbee.songs.client.ui;

import java.util.List;

import javax.inject.Inject;

import com.appbee.core.client.cell.CustomEditTextCell;
import com.appbee.core.client.cell.StyleButtonCell;
import com.appbee.core.client.design.PageStyle;
import com.appbee.core.client.design.celltable.CellTableResources;
import com.appbee.core.client.listener.ValueChangeListener;
import com.appbee.gdata.youtube.client.cell.SimpleEntryCell;
import com.appbee.gdata.youtube.client.design.cells.YoutubeCellListResources;
import com.appbee.gdata.youtube.client.model.SimpleEntry;
import com.appbee.gdata.youtube.client.ui.EmbeddedPlayer;
import com.appbee.songs.client.presenter.ISongSelectionPresenter;
import com.appbee.songs.client.presenter.ISongsDataPresenter;
import com.appbee.songs.client.text.SongsStrings;
import com.appbee.songs.shared.SongProxy;
import com.appbee.user.client.AccessControl;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.cellview.client.CellList;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent;
import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.cellview.client.SimplePager.TextLocation;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;

public class SongsView extends Composite implements ISongsTableView,
		ValueChangeListener
{

	private static SongsViewUiBinder uiBinder = GWT
			.create(SongsViewUiBinder.class);

	interface SongsViewUiBinder extends UiBinder<Widget, SongsView>
	{
	}

	private final SingleSelectionModel<SongProxy> selectionModel;
	private final SingleSelectionModel<SimpleEntry> tubeSelectionModel;

	@UiField
	Button createButton;
	
	@UiField
	Element playerpanel;

	@UiField(provided=true)
	SongSearchView searchBox;
	
	@UiField(provided = true)
	CellTable<SongProxy> cellTable;

	@UiField(provided = true)
	SimplePager pager;
	
	@UiField(provided=true)
	PageStyle style;
	
	@UiField(provided = true)
	ISongsStyle songsStyle;

	@UiField
	EmbeddedPlayer player;
	
	@UiField
	HTML lyrics;
	@UiField
	Button selectVideo;
	private final CellList<SimpleEntry> tubeList;
	private final PopupPanel videoPopup = new PopupPanel();

	private final boolean editMode;
	private final CellTableResources tableRes;

	@UiField(provided = true)
	SongsStrings songsStrings;

	private ISongsDataPresenter presenter;
	private ISongSelectionPresenter songSelectionPresenter;

	@Inject
	public SongsView(	SongSearchView searchBox,
						SongsStrings songsStrings,
						PageStyle style,
						ISongsStyle songsStyle,
						SimpleEntryCell entryCell,
						YoutubeCellListResources cellRes,
						CellTableResources tableRes,
						AccessControl accessControl)
	{
		this.searchBox = searchBox;
		this.songsStrings = songsStrings;
		this.style = style;
		this.songsStyle = songsStyle;
		this.tableRes = tableRes;
		this.editMode = accessControl.isMemberOrAdmin();
		this.tubeList = new CellList<SimpleEntry>(entryCell,cellRes);
		videoPopup.setWidget(tubeList);
		videoPopup.setAutoHideEnabled(true);
		videoPopup.setWidth("396px");
		
		tubeSelectionModel = new SingleSelectionModel<SimpleEntry>();
		tubeList.setSelectionModel(tubeSelectionModel);
		tubeList.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.BOUND_TO_SELECTION);
		selectionModel = new SingleSelectionModel<SongProxy>();
		cellTable = new CellTable<SongProxy>(15, tableRes);
		cellTable.setSelectionModel(selectionModel);
		cellTable.setWidth("100%", true);
		addColumns();
		// Create a Pager to control the table.
		SimplePager.Resources pagerResources = GWT
				.create(SimplePager.Resources.class);
		pager = new SimplePager(TextLocation.CENTER, pagerResources, false, 0,
				true);
		pager.setDisplay(cellTable);

		initWidget(uiBinder.createAndBindUi(this));
		
		videoPopup.addAutoHidePartner(selectVideo.getElement());
		createButton.setVisible(false);
		
		if (editMode)
		{
			createButton.setStyleName(style.newButton());
			createButton.setVisible(true);
			createButton.addClickHandler(new ClickHandler()
			{
				
				@Override
				public void onClick(ClickEvent event)
				{
					presenter.onNewSong();
				}
			});
		}
		selectVideo.addClickHandler(new ClickHandler()
		{
			
			@Override
			public void onClick(ClickEvent event)
			{
				if(videoPopup.isShowing())
				{
					videoPopup.hide();
				}
				else
				{
					videoPopup.showRelativeTo(selectVideo);
				}
			}
		});
		selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler()
		{
			
			@Override
			public void onSelectionChange(SelectionChangeEvent event)
			{
				SongProxy selectedObject = selectionModel.getSelectedObject();
						songSelectionPresenter
								.onSelectionChange(selectedObject);
			}
		});
		tubeSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler()
		{
			
			@Override
			public void onSelectionChange(SelectionChangeEvent event)
			{
				player.setSimpleEntry(tubeSelectionModel.getSelectedObject());
			}
		});
		searchBox.setValueChangeListener(this);
	}

	private void addColumns()
	{
		if (editMode)
		{
			ButtonCol editCol = new ButtonCol(tableRes.cellTableStyle()
					.editButton())
			{

				@Override
				public String getValue(SongProxy object)
				{
					return "Edit";
				}

				@Override
				public void onClick(int index, SongProxy object, String value)
				{
					presenter.onEdit(object);
				}
			};
			cellTable.addColumn(editCol);
			cellTable.setColumnWidth(editCol, 40, Unit.PX);
		}
		EditTextCol nrCol = new EditTextCol()
		{

			@Override
			public String getStringValue(SongProxy object)
			{
				return String.valueOf(object.getNumber());
			}

			@Override
			public void setValue(SongProxy object, String value)
			{
				object.setNumber(Integer.parseInt(value));
			}

			@Override
			public String getFieldName()
			{
				return "number";
			}
		};
		cellTable.addColumn(nrCol, songsStrings.numberCol());
		EditTextCol nameCol = new EditTextCol()
		{

			@Override
			public String getStringValue(SongProxy object)
			{
				return object.getName();
			}

			@Override
			public void setValue(SongProxy object, String value)
			{
				object.setName(value);
			}

			@Override
			public String getFieldName()
			{
				return "name";
			}
		};
		cellTable.addColumn(nameCol, songsStrings.nameCol());
		EditTextCol artistCol = new EditTextCol()
		{

			@Override
			public String getStringValue(SongProxy object)
			{
				return object.getArtist();
			}

			@Override
			public void setValue(SongProxy object, String value)
			{
				object.setArtist(value);
			}

			@Override
			public String getFieldName()
			{
				return "artist";
			}

		};
		cellTable.addColumn(artistCol, songsStrings.artistCol());
		EditTextCol albumCol = new EditTextCol()
		{

			@Override
			public String getStringValue(SongProxy object)
			{
				return object.getAlbum();
			}

			@Override
			public void setValue(SongProxy object, String value)
			{
				object.setAlbum(value);
			}

			@Override
			public String getFieldName()
			{
				return "album";
			}
		};
		cellTable.addColumn(albumCol, songsStrings.albumCol());
		EditTextCol releaseYearCol = new EditTextCol()
		{

			@Override
			public String getStringValue(SongProxy object)
			{
				return object.getReleaseYear();
			}

			@Override
			public void setValue(SongProxy song, String value)
			{
				song.setReleaseYear(value);
			}

			@Override
			public String getFieldName()
			{
				return "releaseYear";
			}
		};
		cellTable.addColumn(releaseYearCol, songsStrings.releaseYearCol());

		cellTable.setColumnWidth(nrCol, 40, Unit.PX);
		cellTable.setColumnWidth(nameCol, 40, Unit.PCT);
		cellTable.setColumnWidth(artistCol, 20, Unit.PCT);
		cellTable.setColumnWidth(albumCol, 40, Unit.PCT);
		cellTable.setColumnWidth(releaseYearCol, 80, Unit.PX);

		if (editMode)
		{
			EditTextCol keyToneCol = new EditTextCol()
			{
	
				@Override
				public String getStringValue(SongProxy object)
				{
					return object.getKeyTone() == null ? "" : object
							.getKeyTone();
				}

				@Override
				public void setValue(SongProxy song, String value)
				{
					song.setKeyTone(value);
				}

				@Override
				public String getFieldName()
				{
					return "keyTone";
				}

			};
			cellTable.addColumn(keyToneCol, songsStrings.keyToneCol());
			EditTextCol startingPlayerCol = new EditTextCol()
			{
	
				@Override
				public String getStringValue(SongProxy object)
				{
					return object.getStartingPlayer();
				}

				@Override
				public void setValue(SongProxy song, String value)
				{
					song.setStartingPlayer(value);
				}

				@Override
				public String getFieldName()
				{
					return "startingPlayer";
				}
	
			};
			cellTable.addColumn(startingPlayerCol,
								songsStrings.startingPlayerCol());
			ButtonCol delCol = new ButtonCol(tableRes.cellTableStyle()
					.deleteButton())
			{

				@Override
				public String getValue(SongProxy object)
				{
					return "Delete";
				}

				@Override
				public void onClick(int index, SongProxy object, String value)
				{
					if (Window.confirm(songsStrings.confirmDelete()))
					{
						presenter.onDelete(object);
					}
				}
			};
			cellTable.addColumn(delCol);
			cellTable.setColumnWidth(delCol, 40, Unit.PX);

			cellTable.setColumnWidth(keyToneCol, 50, Unit.PX);
			cellTable.setColumnWidth(startingPlayerCol, 80, Unit.PX);

		}
		cellTable.addColumnSortHandler(new ColumnSortEvent.Handler()
		{
			
			@Override
			public void onColumnSort(ColumnSortEvent event)
			{
				presenter.onColumnSort(event);
			}
		});

	}

	public SongProxy getSelectedObject()
	{
		return selectionModel.getSelectedObject();
	}

	@Override
	public void setPresenter(ISongsDataPresenter presenter)
	{
		this.presenter = presenter;
	}

	@Override
	public void setSongsSelectionPresenter(ISongSelectionPresenter songSelectionPresenter)
	{
		this.songSelectionPresenter = songSelectionPresenter;
	}

	@Override
	public ISongFilterView getFilterView()
	{
		return searchBox;
	}

	@Override
	public HasData<SongProxy> getDataDisplay()
	{
		return cellTable;
	}

	@Override
	public void onValueChange(String value)
	{
		presenter.onSearch();
	}

	@Override
	public void setPlayerPanelShowing(boolean playerPanelShowing)
	{
		playerpanel.setClassName(playerPanelShowing ? songsStyle
				.playerPanelShowing() : songsStyle.playerPanel());
	}

	@Override
	public void setTubeListData(List<SimpleEntry> list)
	{
		tubeList.setRowData(list);
	}

	@Override
	public void setSelectedTube(SimpleEntry simpleEntry)
	{
		tubeSelectionModel.setSelected(simpleEntry, true);
	}

	@Override
	public void clearPlayer()
	{
		player.setSrc(null);
	}

	@Override
	public void setLyrics(String lyricsString)
	{
		lyrics.setHTML(lyricsString);
	}

	@Override
	public void clearSongSelection()
	{
		selectionModel.setSelected(selectionModel.getSelectedObject(), false);
	}

	private abstract class EditTextCol extends Column<SongProxy, String>
			implements SongEditColumn
	{

		public EditTextCol()
		{
			this(true);
		}

		public EditTextCol(boolean sortable)
		{
			super(editMode ? new CustomEditTextCell() : new TextCell());
			setSortable(sortable);
			setFieldUpdater(new FieldUpdater<SongProxy, String>()
			{

				@Override
				public void update(int index, SongProxy object, String value)
				{
					presenter.update(EditTextCol.this, index, object, value);
				}
			});

		}

		@Override
		public String getValue(SongProxy song)
		{
			String stringValue = getStringValue(song);
			return stringValue == null ? "" : stringValue;
		}

		public abstract String getStringValue(SongProxy song);

	}

	private abstract class ButtonCol extends Column<SongProxy, String>
	{

		public ButtonCol(String style)
		{
			super(new StyleButtonCell(style));
			setFieldUpdater(new FieldUpdater<SongProxy, String>()
			{

				@Override
				public void update(int index, SongProxy object, String value)
				{
					onClick(index, object, value);
				}
			});
		}

		public abstract void onClick(int index, SongProxy object, String value);

	}
}
